import logger from '../utils/logger.js'
class ShapeRecognizer {
  constructor() {
      this.shapes = {
          TRIANGLE: 'triangle',
          EQUILATERAL_TRIANGLE: 'equilateral_triangle',
          RIGHT_TRIANGLE: 'right_triangle',
          ISOSCELES_TRIANGLE: 'isosceles_triangle',
          SQUARE: 'square',
          RECTANGLE: 'rectangle',
          FILLED_RECTANGLE: 'filled_rectangle',
          CIRCLE: 'circle',
          FILLED_CIRCLE: 'filled_circle',
          ELLIPSE: 'ellipse',
          FILLED_ELLIPSE: 'filled_ellipse',
          REGULAR_POLYGON: 'regular_polygon',
          PENTAGON: 'pentagon',
          HEXAGON: 'hexagon',
          HEPTAGON: 'heptagon',
          OCTAGON: 'octagon',
          UNKNOWN: 'unknown'
      };
      
      this.tolerances = {
          distance: 5,           // 像素距离容忍度
          angle: 10,             // 角度容忍度（度）
          ratio: 0.005,          // 比例容忍度（0.5%，非常严格）
          circularity: 0.85      // 圆形度阈值
      };
  }
  
  // 主识别函数
  recognizeShapeFromCode(code) {
      try {
          const points = this.executeCodeAndGetPoints(code);
          return this.analyzeShape(points);
      } catch (error) {
          return {
              shape: this.shapes.UNKNOWN,
              confidence: 0,
              error: error.message,
              details: {}
          };
      }
  }
  
  // 执行代码获取轨迹点
  executeCodeAndGetPoints(code) {
      try {
          // 使用judge.js中的CodeTrajectoryValidator来执行代码
          const { CodeTrajectoryValidator } = this.getJudgeValidator();
          const validator = new CodeTrajectoryValidator();
          
          // 执行代码并获取轨迹
          const result = validator.executeCode(code);
          
          // 将轨迹点转换为形状识别需要的格式，保留所有属性
          return result.points.map(point => ({
              x: point.x + 400, // 偏移到画布中心
              y: point.y + 300,
              // 保留原有的所有属性
              ...point
          }));
      } catch (error) {
          logger.error('执行代码失败:', error);
          return [];
      }
  }
  
  // 获取judge.js的验证器
  getJudgeValidator() {
      if (this.judgeValidator) {
          return { CodeTrajectoryValidator: this.judgeValidator };
      }
      
      // 如果没有设置验证器，抛出错误
      throw new Error('CodeTrajectoryValidator not set. Please use the async recognizeUserCode function.');
  }
  
  // 执行绘图代码
  executeDrawingCode(ctx, code) {
      // 创建安全的执行环境
      const safeEnv = {
          ctx: ctx,
          pen: {
              down: () => ctx.beginPath(),
              up: () => ctx.stroke(),
              size: (s) => ctx.lineWidth = s,
              c: (color) => ctx.strokeStyle = color
          },
          fd: (distance) => {
              const x = ctx.currentX || 0;
              const y = ctx.currentY || 0;
              const angle = ctx.currentAngle || 0;
              const rad = angle * Math.PI / 180;
              const newX = x + distance * Math.cos(rad);
              const newY = y + distance * Math.sin(rad);
              
              ctx.lineTo(newX, newY);
              ctx.currentX = newX;
              ctx.currentY = newY;
          },
          bk: (distance) => this.fd(-distance),
          rt: (angle) => {
              ctx.currentAngle = (ctx.currentAngle || 0) + angle;
          },
          lt: (angle) => {
              ctx.currentAngle = (ctx.currentAngle || 0) - angle;
          },
          moveto: (x, y) => {
              ctx.moveTo(x, y);
              ctx.currentX = x;
              ctx.currentY = y;
          },
          lineto: (x, y) => {
              ctx.lineTo(x, y);
              ctx.currentX = x;
              ctx.currentY = y;
          },
          cls: () => {
              ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
              ctx.currentX = 0;
              ctx.currentY = 0;
              ctx.currentAngle = 0;
          }
      };
      
      // 初始位置
      ctx.currentX = 400;
      ctx.currentY = 300;
      ctx.currentAngle = 0;
      ctx.beginPath();
      ctx.moveTo(ctx.currentX, ctx.currentY);
      
      try {
          // 执行代码
          const wrappedCode = `
              (function() {
                  ${code}
              }).call(this);
          `;
          new Function('pen', 'fd', 'bk', 'rt', 'lt', 'moveto', 'lineto', 'cls', wrappedCode)
              .call(safeEnv, safeEnv.pen, safeEnv.fd, safeEnv.bk, safeEnv.rt, safeEnv.lt, 
                    safeEnv.moveto, safeEnv.lineto, safeEnv.cls);
          
          ctx.stroke();
      } catch (error) {
          logger.warn('代码执行错误:', error);
      }
  }
  
  // 从画布提取轮廓点
  extractContourPoints(canvas) {
      const ctx = canvas.getContext('2d');
      const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
      const points = [];
      
      // 简单的轮廓提取：找到所有非背景像素
      for (let y = 0; y < canvas.height; y++) {
          for (let x = 0; x < canvas.width; x++) {
              const alpha = this.getPixelAlpha(imageData, x, y);
              if (alpha > 10) { // 非透明像素
                  points.push({ x, y });
              }
          }
      }
      
      return this.simplifyPoints(points);
  }
  
  getPixelAlpha(imageData, x, y) {
      const index = (y * imageData.width + x) * 4;
      return imageData.data[index + 3];
  }
  
  // 简化点集，减少计算量
  simplifyPoints(points, tolerance = 5) {
      if (points.length <= 10) return points;
      
      const simplified = [points[0]];
      let lastPoint = points[0];
      
      for (let i = 1; i < points.length; i++) {
          const distance = Math.sqrt(
              Math.pow(points[i].x - lastPoint.x, 2) + 
              Math.pow(points[i].y - lastPoint.y, 2)
          );
          
          if (distance >= tolerance) {
              simplified.push(points[i]);
              lastPoint = points[i];
          }
      }
      
      return simplified;
  }
  
  // 分析形状
  analyzeShape(points) {
      if (points.length < 3) {
          return {
              shape: this.shapes.UNKNOWN,
              confidence: 0,
              details: { reason: '点数不足' }
          };
      }
      
      // 检查是否有预定义的形状类型
      const shapeTypes = points.filter(p => p.shapeType).map(p => p.shapeType);
      if (shapeTypes.length > 0) {
          const shapeType = shapeTypes[0]; // 使用第一个找到的形状类型
          
          // 根据形状类型返回相应的结果
          switch (shapeType) {
              case 'circle':
                  return {
                      shape: this.shapes.CIRCLE,
                      confidence: 0.95,
                      details: {
                          radius: points.find(p => p.radius)?.radius || 50,
                          circularity: 0.99,
                          filled: false
                      }
                  };
              case 'filled_circle':
                  return {
                      shape: this.shapes.FILLED_CIRCLE,
                      confidence: 0.95,
                      details: {
                          radius: points.find(p => p.radius)?.radius || 50,
                          circularity: 0.99,
                          filled: true
                      }
                  };
              case 'ellipse':
                  return {
                      shape: this.shapes.ELLIPSE,
                      confidence: 0.95,
                      details: {
                          width: points.find(p => p.width)?.width || 80,
                          height: points.find(p => p.height)?.height || 50,
                          filled: false
                      }
                  };
              case 'filled_ellipse':
                  return {
                      shape: this.shapes.FILLED_ELLIPSE,
                      confidence: 0.95,
                      details: {
                          width: points.find(p => p.width)?.width || 80,
                          height: points.find(p => p.height)?.height || 50,
                          filled: true
                      }
                  };
              case 'rectangle':
                  return {
                      shape: this.shapes.RECTANGLE,
                      confidence: 0.95,
                      details: {
                          width: points.find(p => p.width)?.width || 100,
                          height: points.find(p => p.height)?.height || 60,
                          filled: false
                      }
                  };
              case 'filled_rectangle':
                  return {
                      shape: this.shapes.FILLED_RECTANGLE,
                      confidence: 0.95,
                      details: {
                          width: points.find(p => p.width)?.width || 100,
                          height: points.find(p => p.height)?.height || 60,
                          filled: true
                      }
                  };
          }
      }
      
      // 计算形状特征
      const features = this.calculateShapeFeatures(points);
      
      // 识别形状
      return this.identifyShapeFromFeatures(features);
  }
  
  // 计算形状特征
  calculateShapeFeatures(points) {
      const convexHull = this.computeConvexHull(points);
      const sides = this.detectSides(convexHull);
      const area = this.calculateArea(convexHull);
      const perimeter = this.calculatePerimeter(convexHull);
      const circularity = this.calculateCircularity(area, perimeter);
      const boundingBox = this.calculateBoundingBox(convexHull);
      const aspectRatio = boundingBox.width / boundingBox.height;
      
      return {
          convexHull,
          sides,
          vertexCount: convexHull.length,
          sideCount: sides.length,
          area,
          perimeter,
          circularity,
          boundingBox,
          aspectRatio,
          sideLengths: sides.map(side => side.length),
          angles: this.calculateAngles(convexHull)
      };
  }
  
  // 计算凸包
  computeConvexHull(points) {
      if (points.length <= 3) return points;
      
      // 按x坐标排序
      points.sort((a, b) => a.x - b.x || a.y - b.y);
      
      const lower = [];
      const upper = [];
      
      // 构建下凸包
      for (const point of points) {
          while (lower.length >= 2 && this.cross(lower[lower.length - 2], lower[lower.length - 1], point) <= 0) {
              lower.pop();
          }
          lower.push(point);
      }
      
      // 构建上凸包
      for (let i = points.length - 1; i >= 0; i--) {
          while (upper.length >= 2 && this.cross(upper[upper.length - 2], upper[upper.length - 1], points[i]) <= 0) {
              upper.pop();
          }
          upper.push(points[i]);
      }
      
      // 合并凸包（移除重复点）
      lower.pop();
      upper.pop();
      return lower.concat(upper);
  }
  
  cross(o, a, b) {
      return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
  }
  
  // 检测边
  detectSides(hull) {
      const sides = [];
      
      for (let i = 0; i < hull.length; i++) {
          const p1 = hull[i];
          const p2 = hull[(i + 1) % hull.length];
          const length = Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
          
          sides.push({
              start: p1,
              end: p2,
              length: length,
              angle: Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI
          });
      }
      
      return sides;
  }
  
  // 计算面积
  calculateArea(points) {
      let area = 0;
      for (let i = 0; i < points.length; i++) {
          const j = (i + 1) % points.length;
          area += points[i].x * points[j].y - points[j].x * points[i].y;
      }
      return Math.abs(area) / 2;
  }
  
  // 计算周长
  calculatePerimeter(points) {
      let perimeter = 0;
      for (let i = 0; i < points.length; i++) {
          const j = (i + 1) % points.length;
          perimeter += Math.sqrt(
              Math.pow(points[j].x - points[i].x, 2) + 
              Math.pow(points[j].y - points[i].y, 2)
          );
      }
      return perimeter;
  }
  
  // 计算圆形度
  calculateCircularity(area, perimeter) {
      if (perimeter === 0) return 0;
      const circlePerimeter = 2 * Math.sqrt(Math.PI * area);
      return circlePerimeter / perimeter;
  }
  
  // 计算边界框
  calculateBoundingBox(points) {
      let minX = Infinity, minY = Infinity;
      let maxX = -Infinity, maxY = -Infinity;
      
      for (const point of points) {
          minX = Math.min(minX, point.x);
          minY = Math.min(minY, point.y);
          maxX = Math.max(maxX, point.x);
          maxY = Math.max(maxY, point.y);
      }
      
      return {
          x: minX,
          y: minY,
          width: maxX - minX,
          height: maxY - minY
      };
  }
  
  // 计算角度
  calculateAngles(points) {
      const angles = [];
      
      for (let i = 0; i < points.length; i++) {
          const a = points[i];
          const b = points[(i + 1) % points.length];
          const c = points[(i + 2) % points.length];
          
          const ab = { x: b.x - a.x, y: b.y - a.y };
          const bc = { x: c.x - b.x, y: c.y - b.y };
          
          const dot = ab.x * bc.x + ab.y * bc.y;
          const magAB = Math.sqrt(ab.x * ab.x + ab.y * ab.y);
          const magBC = Math.sqrt(bc.x * bc.x + bc.y * bc.y);
          
          let angle = Math.acos(dot / (magAB * magBC)) * 180 / Math.PI;
          if (isNaN(angle)) angle = 0;
          
          // 对于逆时针绘制的多边形，计算内角
          // 使用叉积判断方向，如果是逆时针，则角度是正确的内角
          const cross = ab.x * bc.y - ab.y * bc.x;
          if (cross > 0) {
              // 逆时针，角度需要转换为内角
              angle = 180 - angle;
          }
          
          angles.push(angle);
      }
      
      return angles;
  }
  
  // 根据特征识别形状
  identifyShapeFromFeatures(features) {
      const { vertexCount, sideCount, circularity, sideLengths, angles, aspectRatio, area, boundingBox } = features;
      
      // 检查是否是圆形
      if (this.isCircle(features)) {
          return this.checkCircleType(features);
      }
      
      // 检查正多边形
      const regularPolygon = this.checkRegularPolygon(features);
      if (regularPolygon) {
          return regularPolygon;
      }
      
      // 检查三角形
      if (vertexCount === 3) {
          return this.identifyTriangle(features);
      }
      
      // 检查四边形
      if (vertexCount === 4) {
          return this.identifyQuadrilateral(features);
      }
      
      return {
          shape: this.shapes.UNKNOWN,
          confidence: 0.3,
          details: {
              vertexCount,
              sideCount,
              circularity: Math.round(circularity * 100) / 100,
              reason: '无法识别的形状'
          }
      };
  }
  
  // 检查圆形
  isCircle(features) {
      return features.circularity > this.tolerances.circularity && features.vertexCount > 8;
  }
  
  // 检查圆形类型
  checkCircleType(features) {
      const filledRatio = features.area / (features.boundingBox.width * features.boundingBox.height);
      const isFilled = filledRatio > 0.7;
      
      return {
          shape: isFilled ? this.shapes.FILLED_CIRCLE : this.shapes.CIRCLE,
          confidence: 0.95,
          details: {
              radius: Math.round((features.boundingBox.width + features.boundingBox.height) / 4),
              circularity: Math.round(features.circularity * 100) / 100,
              filled: isFilled,
              area: Math.round(features.area),
              perimeter: Math.round(features.perimeter)
          }
      };
  }
  
  // 检查正多边形
  checkRegularPolygon(features) {
      const { sideLengths, angles, vertexCount } = features;
      
      if (vertexCount < 3 || vertexCount > 12) return null;
      
      // 检查边长是否相等（使用与areSidesEqual相同的逻辑）
      const firstSide = sideLengths[0];
      const sidesEqual = sideLengths.every(len => Math.abs(len - firstSide) / firstSide < this.tolerances.ratio);
      
      // 检查角度是否相等
      const expectedAngle = 180 - (360 / vertexCount);
      const angleVariance = angles.reduce((variance, angle) => {
          return variance + Math.pow(angle - expectedAngle, 2);
      }, 0) / angles.length;
      
      const isRegular = sidesEqual && Math.sqrt(angleVariance) < this.tolerances.angle * 2; // 放宽角度容忍度
      
      if (isRegular) {
          let shapeName;
          switch (vertexCount) {
              case 3: shapeName = this.shapes.EQUILATERAL_TRIANGLE; break;
              case 4: shapeName = this.shapes.SQUARE; break;
              case 5: shapeName = this.shapes.PENTAGON; break;
              case 6: shapeName = this.shapes.HEXAGON; break;
              case 7: shapeName = this.shapes.HEPTAGON; break;
              case 8: shapeName = this.shapes.OCTAGON; break;
              default: shapeName = this.shapes.REGULAR_POLYGON;
          }
          
          return {
              shape: shapeName,
              confidence: 0.9,
              details: {
                  sides: vertexCount,
                  sideLength: Math.round(firstSide),
                  internalAngle: Math.round(expectedAngle),
                  area: Math.round(features.area)
              }
          };
      }
      
      return null;
  }
  
  // 识别三角形类型
  identifyTriangle(features) {
      const { sideLengths, angles } = features;
      const [a, b, c] = sideLengths;
      
      // 检查等边三角形
      if (this.areSidesEqual(sideLengths)) {
          return {
              shape: this.shapes.EQUILATERAL_TRIANGLE,
              confidence: 0.95,
              details: {
                  sideLength: Math.round(a),
                  angles: angles.map(ang => Math.round(ang)),
                  area: Math.round(features.area)
              }
          };
      }
      
      // 检查等腰三角形
      if (this.isIsosceles(sideLengths)) {
          return {
              shape: this.shapes.ISOSCELES_TRIANGLE,
              confidence: 0.85,
              details: {
                  sideLengths: sideLengths.map(len => Math.round(len)),
                  angles: angles.map(ang => Math.round(ang)),
                  area: Math.round(features.area)
              }
          };
      }
      
      // 检查直角三角形
      if (this.isRightTriangle(angles)) {
          return {
              shape: this.shapes.RIGHT_TRIANGLE,
              confidence: 0.8,
              details: {
                  sideLengths: sideLengths.map(len => Math.round(len)),
                  angles: angles.map(ang => Math.round(ang)),
                  area: Math.round(features.area)
              }
          };
      }
      
      // 普通三角形
      return {
          shape: this.shapes.TRIANGLE,
          confidence: 0.7,
          details: {
              sideLengths: sideLengths.map(len => Math.round(len)),
              angles: angles.map(ang => Math.round(ang)),
              area: Math.round(features.area)
          }
      };
  }
  
  // 识别四边形类型
  identifyQuadrilateral(features) {
      const { sideLengths, angles, aspectRatio } = features;
      const [a, b, c, d] = sideLengths;
      
      // 先检查是否是矩形（对边相等，角度为直角）
      if (this.isRectangle(sideLengths, angles)) {
          // 再检查是否是正方形（所有边都相等）
          if (this.areSidesEqual(sideLengths)) {
              return {
                  shape: this.shapes.SQUARE,
                  confidence: 0.95,
                  details: {
                      sideLength: Math.round(a),
                      area: Math.round(features.area)
                  }
              };
          } else {
              // 是矩形但不是正方形
              return {
                  shape: this.shapes.RECTANGLE,
                  confidence: 0.9,
                  details: {
                      width: Math.round(Math.max(a, b)),
                      height: Math.round(Math.min(a, b)),
                      aspectRatio: Math.round(aspectRatio * 100) / 100,
                      area: Math.round(features.area)
                  }
              };
          }
      }
      
      return {
          shape: this.shapes.UNKNOWN,
          confidence: 0.5,
          details: {
              sideLengths: sideLengths.map(len => Math.round(len)),
              angles: angles.map(ang => Math.round(ang)),
              reason: '无法识别的四边形'
          }
      };
  }
  
  // 辅助方法
  areSidesEqual(lengths) {
      // 更严格的判断：以第一条边为基准，检查其他边是否与之相等
      const firstSide = lengths[0];
      return lengths.every(len => Math.abs(len - firstSide) / firstSide < this.tolerances.ratio);
  }
  
  isIsosceles(lengths) {
      const sorted = [...lengths].sort((a, b) => a - b);
      return Math.abs(sorted[0] - sorted[1]) / sorted[0] < this.tolerances.ratio || 
             Math.abs(sorted[1] - sorted[2]) / sorted[1] < this.tolerances.ratio;
  }
  
  isRightTriangle(angles) {
      return angles.some(angle => Math.abs(angle - 90) < this.tolerances.angle);
  }
  
  areAnglesRight(angles) {
      return angles.every(angle => Math.abs(angle - 90) < this.tolerances.angle);
  }
  
  isRectangle(sideLengths, angles) {
      const [a, b, c, d] = sideLengths;
      return Math.abs(a - c) / a < this.tolerances.ratio && 
             Math.abs(b - d) / b < this.tolerances.ratio && 
             this.areAnglesRight(angles);
  }
}

// // 使用示例
// const recognizer = new ShapeRecognizer();

// // 测试函数
// function testShapeRecognition() {
//   const testCases = [
//       {
//           name: '正方形',
//           code: `
//               fd(100); rt(90);
//               fd(100); rt(90);
//               fd(100); rt(90);
//               fd(100);
//           `
//       },
//       {
//           name: '等边三角形',
//           code: `
//               fd(100); lt(120);
//               fd(100); lt(120);
//               fd(100);
//           `
//       },
//       {
//           name: '圆形',
//           code: `
//               for(let i=0;i<36;i++) {
//                   fd(10); rt(10);
//               }
//           `
//       },
//       {
//           name: '矩形',
//           code: `
//               fd(150); rt(90);
//               fd(80); rt(90);
//               fd(150); rt(90);
//               fd(80);
//           `
//       },
//       {
//           name: '正五边形',
//           code: `
//               for(let i=0;i<5;i++) {
//                   fd(80); rt(72);
//               }
//           `
//       },
//       {
//           name: '正六边形',
//           code: `
//               for(let i=0;i<6;i++) {
//                   fd(70); rt(60);
//               }
//           `
//       }
//   ];
  
//   testCases.forEach(testCase => {
//       const result = recognizer.recognizeShapeFromCode(testCase.code);
//       logger.log(`${testCase.name}:`, result);
//   });
// }

// // 执行测试
// testShapeRecognition();

// 导出函数
export async function recognizeUserCode(userCode) {
  try {
    // 动态导入judge.js
    const { CodeTrajectoryValidator } = await import('./judge.js');
    
    // 创建形状识别器并设置judge验证器
    const recognizer = new ShapeRecognizer();
    recognizer.judgeValidator = CodeTrajectoryValidator;
    
    const result = recognizer.recognizeShapeFromCode(userCode);
    
    logger.log('🔍 形状识别结果:');
    logger.log(`📐 形状: ${result.shape}`);
    logger.log(`📊 置信度: ${Math.round(result.confidence * 100)}%`);
    logger.log('📋 详细信息:', result.details);
    
    return result;
  } catch (error) {
    logger.error('形状识别失败:', error);
    return {
      shape: 'unknown',
      confidence: 0,
      error: error.message,
      details: {}
    };
  }
}

// 也导出类本身
export { ShapeRecognizer };

// 默认导出
export default { recognizeUserCode, ShapeRecognizer };

